package com.wteam.framework.common.security.token;

import com.wteam.framework.common.cache.Cache;
import com.wteam.framework.common.cache.CachePrefix;
import com.wteam.framework.common.enums.ResultCode;
import com.wteam.framework.common.exception.ServiceException;
import com.wteam.framework.common.properties.JWTTokenProperties;
import com.wteam.framework.common.security.enums.UserEnums;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.SignatureException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@Component
public class myTokenUtil {
    @Autowired
    private JWTTokenProperties tokenProperties;
    @Autowired
    private Cache cache;

    public Token createToken(Map<String, Object> claims, boolean longTerm, UserEnums userEnums) {
        Token token = new Token();
        //访问token
        String accessToken = createToken(claims, tokenProperties.getTokenExpireTime());

        cache.put(CachePrefix.ACCESS_TOKEN.getPrefix(userEnums) + accessToken, 1,
                tokenProperties.getTokenExpireTime(), TimeUnit.MINUTES);
        //刷新token生成策略：如果是长时间有效的token（用于app），则默认15天有效期刷新token。如果是普通用户登录，则刷新token为普通token2倍数
        Long expireTime = longTerm ? 15 * 24 * 60L : tokenProperties.getTokenExpireTime() * 2;
        String refreshToken = createreflushToken(claims, expireTime);

        cache.put(CachePrefix.REFRESH_TOKEN.getPrefix(userEnums) + refreshToken, 1, expireTime, TimeUnit.MINUTES);

        token.setAccessToken(accessToken);
        token.setRefreshToken(refreshToken);
        return token;
    }

    /**
     * 刷新token
     *
     * @param oldRefreshToken 刷新token
     * @param userEnums       用户枚举
     * @return token
     */
    public Token  refreshToken(String oldRefreshToken, UserEnums userEnums) {

        Map<String, Object> claims;
        try {
            claims = myTokenUtil.reflushparseJWT(oldRefreshToken);
        } catch (ExpiredJwtException | UnsupportedJwtException | MalformedJwtException | SignatureException | IllegalArgumentException e) {
            //token 过期 认证失败等
            throw new ServiceException(ResultCode.USER_AUTH_EXPIRED);
        }




        //如果缓存中有刷新token &&
        if (cache.hasKey(CachePrefix.REFRESH_TOKEN.getPrefix(userEnums) + oldRefreshToken)) {
            Token token = new Token();
            //访问token
            String accessToken = createToken(claims, tokenProperties.getTokenExpireTime());
            cache.put(CachePrefix.ACCESS_TOKEN.getPrefix(userEnums) + accessToken, 1, tokenProperties.getTokenExpireTime(), TimeUnit.MINUTES);

            //如果是信任登录设备，则刷新token长度继续延长
            Long expirationTime = tokenProperties.getTokenExpireTime() * 2;
            if (true) {
                expirationTime = 60 * 24 * 15L;
            }

            //刷新token生成策略：如果是长时间有效的token（用于app），则默认15天有效期刷新token。如果是普通用户登录，则刷新token为普通token2倍数
            String refreshToken = createreflushToken(claims, expirationTime);

            cache.put(CachePrefix.REFRESH_TOKEN.getPrefix(userEnums) + refreshToken, 1, expirationTime, TimeUnit.MINUTES);
            token.setAccessToken(accessToken);
            token.setRefreshToken(refreshToken);
            cache.remove(CachePrefix.REFRESH_TOKEN.getPrefix(userEnums) + oldRefreshToken);
            return token;
        } else {
            throw new ServiceException(ResultCode.USER_AUTH_EXPIRED);
        }

    }


    private String createToken(Map<String, Object> claims, Long expirationTime) {
        //JWT 生成
        String jwt = Jwts.builder()
                .addClaims(claims)
                .signWith(SecretKeyUtil.generalKey())
                .setExpiration(new Date(System.currentTimeMillis() + expirationTime * 60 * 1000))
                .compact();
        return jwt;
    }

    /**
     * 解析JWT令牌
     *
     * @param jwt JWT令牌
     * @return JWT第二部分负载 payload 中存储的内容
     */
    public static Claims parseJWT(String jwt) {
        Claims claims = Jwts.parser()
                .setSigningKey(SecretKeyUtil.generalKey())
                .parseClaimsJws(jwt)
                .getBody();
        return claims;
    }

    private String createreflushToken(Map<String, Object> claims, Long expirationTime) {
        //JWT 生成
        String jwt = Jwts.builder()
                .addClaims(claims)
                .signWith(SecretKeyUtil.reflushgeneralKey())
                .setExpiration(new Date(System.currentTimeMillis() + expirationTime * 60 * 1000))
                .compact();
        return jwt;
    }
    /**
     * 解析JWT令牌
     *
     * @param jwt JWT令牌
     * @return JWT第二部分负载 payload 中存储的内容
     */
    public static Claims reflushparseJWT(String jwt) {
        Claims claims = Jwts.parser()
                .setSigningKey(SecretKeyUtil.reflushgeneralKey())
                .parseClaimsJws(jwt)
                .getBody();
        return claims;
    }
}
